package com.applet.exceptionhandler;

import com.alibaba.druid.sql.visitor.functions.Bin;
import com.applet.constant.MessageConstant;
import com.applet.exception.BaseException;
import com.applet.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 全局异常捕获
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    /**
     * 捕获业务异常
     */
    @ExceptionHandler(value = BaseException.class)
    public Result baseException(BaseException ex){
        log.info("业务异常: {}", ex.getMessage());
        return Result.error(ex.getMessage());
    }




    /**
     * 使用@Validated 或 @Valid 注解  校验Json参数
     *                              全局异常捕获
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidException(MethodArgumentNotValidException ex){
        //获取封装的异常信息
        List<ObjectError> allErrors = ex.getAllErrors();
        if( !CollectionUtils.isEmpty(allErrors) ){
            String exception = allErrors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
            return Result.error(exception);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }



    /**
     *  使用@Validated 或 @Valid 注解    校验路径拼接参数  url?name=xxx&age=xxx  定义形参接收
     *                                                 形参上  未添加@RequestParam 注解
     *                                全局异常捕获
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Result constraintViolationException(ConstraintViolationException ex){
        //获取封装的异常信息
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if(!CollectionUtils.isEmpty(constraintViolations)){
            String exception = constraintViolations.stream().map(ConstraintViolation::getMessageTemplate).collect(Collectors.joining(";"));
            return Result.error(exception);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }



    /**
     * 使用@Validated 或 @Valid 注解  校验路径参数  url?name=xxx&age=xxx 定义形参接收
     *                                           形参上  添加@RequestParam 注解
     *                                           全局异常捕获
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public Result missingServletRequestParameterException(MissingServletRequestParameterException ex){
        //获取封装的异常信息
        String parameterType = ex.getParameterType();
        String parameterName = ex.getParameterName();
        return Result.error(parameterType + " " + parameterName + "is null");
    }




    /**
     * 使用@Validated 或 @Valid 注解   路径拼接参数 url?name=xxx&age=xxx   实体类接收
     *                               全局异常捕获
     */
    @ExceptionHandler(value = BindException.class)
    public Result bindException(BindException ex){
        //获取封装的异常
        BindingResult bindingResult = ex.getBindingResult();
        if(Objects.nonNull(bindingResult) && bindingResult.hasErrors()){
            String exception = bindingResult.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";"));
            return Result.error(exception);
        }
        return Result.error(MessageConstant.PARAMETER_IS_NULL);
    }




}
